
#include "stdint.h"
#include "wrap.h"
#include<sys/time.h>
//---------------------------------------------------------------------------

#ifndef IEC104H
#define IEC104H


#define t0 30 //建立连接的超时：s
#define t1 15 //发送或测试APDU的超时
#define t2 10  //无数据报文确认的超时
#define t3  20 //长期空闲状态下发送测试帧的超时
#define  k   12  //发送序号变量和接受序号变量的最大差值
#define  w   8    //最迟接收到w个I模式后APDU给出确认帧


#define  U_PKG  3   //U帧为控制帧，用于控制启动/停止/测试，长度为6个字节，为短帧；   
#define  S_PKG  2 // S帧为确认帧，用于确认接收的I帧，长度为6个字节
#define  I_PKG  1 //I帧为信息帧，用于传输数据，长度大于6个字节
//--------------------------------类型标识TYP-------------------------------------------
/*--------
1、遥测：远程测量。是指采集并传送运行参数，包括各种电气量(线路上的电压、电流、功率等量值) 和负荷潮流等。

2、遥信：远程信号。是指采集并传送各种保护和开关量信息。

3、遥控：远程控制。是指接受并执行遥控命令，主要是分合闸，对远程的一些开关控制设备进行远程控制。

4、遥调：远程调节。是指接受并执行遥调命令，对远程的控制量设备进行远程调试，如调节发电机输出功率。

*/
/*遥测*/
#define TYP_Telemetry_09     0x09			//带品质描述的测量值，每个遥测值占3个字节
#define TYP_Telemetry_0a     0x0a			//带3个字节时标的且具有品质描述的测量值，每个遥测值占6个字节
#define TYP_Telemetry_0b      0x0b           //不带时标的标度化值，每个遥测值占3个字节
#define TYP_Telemetry_0c      0x0c           //带3个时标的标度化值，每个遥测值占6个字节
#define TYP_Telemetry_0d      0x0d           //带品质描述的浮点值，每个遥测值占5个字节
#define TYP_Telemetry_0e      0x0e           //带3个字节时标且具有品质描述的浮点值，每个遥测值占8个字节
#define TYP_Telemetry_15      0x15           //不带品质描述的遥测值，每个遥测值占2个字节

/*遥信*/
#define TYP_Telesignaling_01      0x01           //不带时标的单点遥信，每个遥信占1个字节
#define TYP_Telesignaling_03      0x03           //不带时标的双点遥信，每个遥信占1个字节
#define TYP_Telesignaling_14      0x14           //具有状态变位检出的成组单点遥信，每个字节8个遥信

/*SOE*/
#define TYP_SOE_02      0x02          //带3个字节短时标的单点遥信,1+3
#define TYP_SOE_04      0x04          //带3个字节短时标的双点遥信
#define TYP_SOE_1e      0x1e          //带7个字节时标的单点遥信
#define TYP_SOE_1f      0x1f          //带7个字节时标的双点遥信

/*KWH*/
#define TYP_KWH_0f      0x0f          //不带时标的电能量，每个电能量占5个字节
#define TYP_KWH_10      0x10          //带3个字节短时标的电能量，每个电能量占8个字节
#define TYP_KWH_25      0x25          //带7个字节短时标的电能量，每个电能量占12个字节

/*其他*/
#define TYP_SigngleControl_2d      0x2d          //单点遥控
#define TYP_DoubleControl_2e      0x2e          //双点遥控
#define TYP_DoubleAdjust_2f      0x2f          //双点遥调
#define TYP_FullData_64      0x64         //召唤全数据,总召唤
#define TYP_FullEle_65     0x65          //召唤全电度
#define TYP_Clock_67      0x67          //时钟同步

//--------------------------------传送原因COT-------------------------------------------

#define  Reason_Cycle_1     0x01    //周期、循环
#define  Reason_BackScan_2     0x02    //背景扫描
#define  Reason_Burst_3     0x03    //突发
#define  Reason_Init_4     0x04    //初始化
#define  Reason_Req_5     0x05    //请求或被请求
#define  Reason_Active_6     0x06    //激活
#define  Reason_Active_7     0x07    //激活确认
#define  Reason_Active_8     0x08    //停止激活
#define  Reason_Active_9     0x09    //停止激活确认
#define  Reason_Active_a     0x0a    //激活结束
#define  Reason_ReqCall_14     0x14    //响应总召唤

//----------------------------------------------------------------------------
struct  I_CCM_t { //信息帧
		uint16_t NS;//低位
		uint16_t NR;
	  };
struct S_CCM_t { //确认信息帧
	   uint16_t  S_F;//高位
       uint16_t  NR;
};
struct U_F_t {  //控制帧位
	   uint8_t MsgType:2;  //低地址
	   uint8_t StartDt:2;
	   uint8_t StopDt:2;//高地址  TestFR StopDt StartDt MsgType
	   uint8_t TestFR:2;
};
struct U_CCM_t {//控制帧
	   struct U_F_t U;
	   uint8_t Zero[3];
};
union CCM_t {   //APCI控制位组
	  I_CCM_t  I_CCM;
	  S_CCM_t  S_CCM;
      U_CCM_t  U_CCM;
};
struct VSQbit_t {
	   uint8_t Num: 7;//信息元素个数
	   uint8_t SQ:  1;//可变结构限定词的最高位,为0表示信息元素不按顺序拜访，ASDU中的每个元素=信息体地址+信息值
	   								//为1表示信息元素按顺序摆放，ASDU从第二个数据开始只需给出信息值
	};									
union  VSQ_t {
	   struct VSQbit_t bit;//可变结构限定词
	   uint8_t all;
};
struct COTbit_t {
	   uint8_t COT:6;   //传送原因联合体位数，激活确认 bit0--bit5
	   uint8_t PN:1;
	   uint8_t T:1;
};
union  COT_t {  //传送原因联合体
	   COTbit_t bit;
       uint8_t all; //源发地址，缺省值 0，有效值1-255
};
struct CP56time2a  //size = 7,iv=1,时间无效，su=1夏令时
{
	uint8_t msec[2];
	uint8_t min :6;
	uint8_t res1 :1;
	uint8_t iv :1;
	uint8_t hour :5;
	uint8_t res2 :2;
	uint8_t su :1;
	uint8_t mday :5;
	uint8_t wday :3;
	uint8_t month :4;
	uint8_t res3 :4;
	uint8_t year :7;
	uint8_t res4 :1;
};
struct ASDU_MSG_ADR_t {
	   uint8_t  Adr[3];
};
/*
公共地址字节数：2
传输原因字节数：2
信息体地址字节数：3
或
公共地址字节数：1
传输原因字节数：1
信息体地址字节数：2
*/
struct ASDU_t    
{
	uint8_t TYP;  //类型
	VSQ_t VSQ; //可变结构限定词(信息对象数)
	COT_t COT[2];  //传送原因
//    uint8_t  SA;// 源地址,公共地址
	uint8_t  CommAdr[2];  //公共地址 0 --未用，1---65534  有效值(一般为1---255)，65535 --全局地址
	uint8_t  MsgAdr[3];//信息体地址 D15---D0对应101规约时的信息体地址，D23---D16对应结构化对象信息体地址，不用时取0
	uint8_t  Msg[220];
};
struct  APCI_t
{
	uint8_t  SOM; ////启动字符
	uint8_t  APDU_LEN;//长度
	union CCM_t CCM;//控制位组
 };
 struct APDU_t 
 {
	struct  APCI_t APCI; //APDU = APCI + ASDU
	uint8_t Asdu[300];
};
void IEC104_GetLocalTime(uint8_t *pTime);
int IEC104_CheckPkgType(uint8_t *pApdu);
uint8_t IEC104_ChkIPkgAsduType(uint8_t *pApdu);
int  IEC104_SPkgRespone(uint8_t *pRespone,uint16_t *pSendCNT);
int IEC104_UPkgRespone(uint8_t *pApdu,uint8_t *pRespone);

int IEC104_IPkgResponeAct(uint8_t *pApdu,uint8_t *pRespone,uint16_t *pSendCNT,uint16_t *pRecCNT,bool bAct);//I响应
int IEC104_SendYX(uint8_t *pApdu,uint8_t *pRespone,uint8_t  TYP,uint8_t COT,uint8_t* YXdata,int YXdata_num,int RTUaddrs);//发送YX数据,
int IEC104_SendYC(uint8_t *pApdu,uint8_t *pRespone,uint8_t  TYP,uint8_t COT,uint8_t* YXdata,int YXdata_num,int RTUaddrs);//发送YC数据,
int IEC104_SendKWH(uint8_t *pApdu,uint8_t *pRespone,uint8_t  TYP,uint8_t COT,uint8_t* YXdata,int YXdata_num,int RTUaddrs);//电力数据
//int IEC104_IPkgRespone(uint8_t *pApdu,uint8_t *pRespone,uint16_t *pSendCNT,uint16_t *pRecCNT,uint8_t *pData,uint8_t iLen);
//int  IEC104_IPkg(uint8_t *pApdu,uint8_t *pAsdu,int AsduLen,uint16_t SendCNT,uint16_t RecCNT);
#endif
